CREATE OR REPLACE PACKAGE INTERFACE.FS AUTHID CURRENT_USER IS



  NOT_FOUND                      EXCEPTION;
  COULD_NOT_DELETE               EXCEPTION;
  NON_FILE                       EXCEPTION;
  NON_DIRECTORY                  EXCEPTION;
  INSUFFICIENT_PRIVILEGES        EXCEPTION;
  ENVIRONMENT_VARIABLE_NOT_FOUND EXCEPTION;

  PRAGMA EXCEPTION_INIT (NOT_FOUND,                      -20110);
  PRAGMA EXCEPTION_INIT (COULD_NOT_DELETE,               -20111);
  PRAGMA EXCEPTION_INIT (NON_FILE,                       -20112);
  PRAGMA EXCEPTION_INIT (NON_DIRECTORY,                  -20113);
  PRAGMA EXCEPTION_INIT (INSUFFICIENT_PRIVILEGES,        -20114);
  PRAGMA EXCEPTION_INIT (ENVIRONMENT_VARIABLE_NOT_FOUND, -20116);


  SUBTYPE varchar_type         IS VARCHAR2(1000);
  SUBTYPE path_type            IS VARCHAR_TYPE;
  SUBTYPE paths_type           IS FS_VARCHAR_TABLE_TYPE;
  SUBTYPE name_type            IS PATH_TYPE;
  SUBTYPE names_type           IS PATHS_TYPE;

  SUBTYPE directory_path_type  IS PATH_TYPE;
  SUBTYPE directory_paths_type IS PATHS_TYPE;
  SUBTYPE directory_name_type  IS NAME_TYPE;
  SUBTYPE directory_names_type IS NAMES_TYPE;

  SUBTYPE file_path_type       IS PATH_TYPE;
  SUBTYPE file_paths_type      IS PATHS_TYPE;
  SUBTYPE file_name_type       IS NAME_TYPE;
  SUBTYPE file_names_type      IS NAMES_TYPE;
  SUBTYPE file_line_type       IS VARCHAR_TYPE;
  SUBTYPE file_lines_type      IS FS_VARCHAR_TABLE_TYPE;

  SUBTYPE file_handle_type    IS FS_FILE_HANDLE_TYPE;
  SUBTYPE charset_name_type   IS VARCHAR2(100);
  SUBTYPE error_type          IS FS_ERROR_TYPE;



  -- Returns the name of the file or directory located at <code>path</code>. The
  -- file or directory does not need to exist.
  -- 
  -- %param path The path to the file or directory whose name is to be returned.
  -- %return The name of the file or directory at <code>path</code>.
  FUNCTION name(path PATH_TYPE) RETURN NAME_TYPE;



  -- Returns the base of the name. The base is defined as the portion of the name
  -- up to, but not including, the last period. For example, the base of <code>'test.txt'</code>
  -- is <code>'test'</code>. If the name has no period, the base is simply the name.
  -- 
  -- %param name The name whose base is to be computed
  -- %return The base of <code>name</code>
  FUNCTION base(name NAME_TYPE) RETURN NAME_TYPE;



  -- Returns the extension of the name. The extension is defined as the portion of the name
  -- from the last period onward. For example, the extension of <code>'test.txt'</code>
  -- is <code>'.txt'</code>. If the name has no period, the extension is empty.
  -- 
  -- %param name The name whose extension is to be computed
  -- %return The extension of <code>name</code>
  FUNCTION extension(name NAME_TYPE) RETURN NAME_TYPE;



  -- Determines if the file or directory located at <code>path</code> exists.
  -- 
  -- %param path The path to the file or directory
  -- %return <code>TRUE</code> if the file or directory exists, <code>FALSE</code> otherwise
  -- %see file_exists
  -- %see directory_exists
  FUNCTION exists(path PATH_TYPE) RETURN BOOLEAN;



  -- Determines if the file located at <code>file_path</code> exists.
  -- 
  -- %param file_path The path to the file
  -- %return <code>TRUE</code> if the file exists, <code>FALSE</code> otherwise
  -- %see exists
  -- %see directory_exists
  FUNCTION file_exists(file_path FILE_PATH_TYPE) RETURN BOOLEAN;



  -- Determines if the directory located at <code>path</code> exists.
  -- 
  -- %param directory_path The path to the directory
  -- %return <code>TRUE</code> if the directory exists, <code>FALSE</code> otherwise
  -- %see exists
  -- %see file_exists
  FUNCTION directory_exists(directory_path DIRECTORY_PATH_TYPE) RETURN BOOLEAN;



  -- Builds a new path by appending <code>relative_path</code> onto <code>base_path</code>.
  -- For example:
  -- 
  -- <code>
  -- append_to_path('/home/bill', 'test.txt') = '/home/bill/test.txt'
  -- </code>
  -- 
  -- %param base_path The base path.
  -- %param relative_path The relative path to append onto <code>base_path</code>.
  -- %return The new path built by appending the relative path onto the base path.
  FUNCTION append_to_path(base_path PATH_TYPE, relative_path PATH_TYPE) RETURN PATH_TYPE;



  -- Returns the name of the file located at <code>file_path</code>.
  -- 
  -- %param The path to the file whose name is to be returned.
  -- %return The name of the file at <code>file_path</code>.
  -- %raises NON_FILE Raised if <code>file_path</code> exists, but it is not a file.
  FUNCTION file_name(file_path FILE_PATH_TYPE) RETURN FILE_NAME_TYPE;



  -- Determines the size of the file located at <code>file_path</code> (in bytes).
  -- 
  -- %param file_path The path to the file whose size is to be returned.
  -- %return The size of the file (in bytes).
  -- %raises NON_FILE Raised if <code>file_path</code> exists, but it is not a file.
  FUNCTION file_size(file_path FILE_PATH_TYPE) RETURN NUMBER;



  -- Returns the name of the directory located at <code>directory_path</code>.
  -- 
  -- %param The path to the directory whose name is to be returned.
  -- %return The name of the directory at <code>file_path</code>.
  -- %raises NON_DIRECTORY Raised if <code>directory_path</code> exists, but it is not a directory.
  FUNCTION directory_name(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_NAME_TYPE;



  FUNCTION resolve_path(path PATH_TYPE) RETURN PATH_TYPE;

  -- Effectively the same as <code>absolute_path(resolve_path(path))</code>.
  FUNCTION absolute_path(path PATH_TYPE) RETURN PATH_TYPE;

  FUNCTION canonical_path(path PATH_TYPE) RETURN PATH_TYPE;



  FUNCTION resolve_file_path(file_path FILE_PATH_TYPE) RETURN FILE_PATH_TYPE;

  FUNCTION absolute_file_path(file_path FILE_PATH_TYPE) RETURN FILE_PATH_TYPE;

  FUNCTION canonical_file_path(file_path FILE_PATH_TYPE) RETURN FILE_PATH_TYPE;



  FUNCTION resolve_directory_path(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_PATH_TYPE;

  FUNCTION absolute_directory_path(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_PATH_TYPE;

  FUNCTION canonical_directory_path(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_PATH_TYPE;



  -- Deletes the file or directory located at <code>path</code>.
  -- 
  -- %param path
  PROCEDURE delete(path PATH_TYPE);



  -- Deletes the file located at <code>file_path</code>.
  -- 
  -- %param file_path
  -- %raises NON_FILE Raised if <code>file_path</code> exists, but it is not a file.
  PROCEDURE delete_file(file_path FILE_PATH_TYPE);



  -- Deletes the directory located at <code>directory_path</code>.
  -- 
  -- %param directory_path
  -- %raises NON_DIRECTORY Raised if <code>directory_path</code> exists, but it is not a directory.
  PROCEDURE delete_directory(directory_path DIRECTORY_PATH_TYPE);



  -- Lists the names of all the files and/or subdirectories contained within <code>directory_path</code>.
  -- 
  -- %raises NOT_FOUND If <code>directory_path</code> does not exist.
  -- %raises NON_DIRECTORY Raised if <code>directory_path</code> exists, but it is not a directory.
  FUNCTION list_names(directory_path DIRECTORY_PATH_TYPE) RETURN NAMES_TYPE;
  FUNCTION list_names(directory_path DIRECTORY_PATH_TYPE, pattern VARCHAR2) RETURN NAMES_TYPE;



  -- Lists the paths of all the files and/or subdirectories contained within <code>directory_path</code>.
  -- 
  -- %raises NOT_FOUND If <code>directory_path</code> does not exist.
  -- %raises NON_DIRECTORY Raised if <code>directory_path</code> exists, but it is not a directory.
  FUNCTION list_paths(directory_path DIRECTORY_PATH_TYPE) RETURN PATHS_TYPE;
  FUNCTION list_paths(directory_path DIRECTORY_PATH_TYPE, pattern VARCHAR2) RETURN PATHS_TYPE;



  -- Lists the names of all the files within <code>directory_path</code>.
  -- 
  -- %raises NOT_FOUND If <code>directory_path</code> does not exist.
  -- %raises NON_DIRECTORY Raised if <code>directory_path</code> exists, but it is not a directory.
  FUNCTION list_file_names(directory_path DIRECTORY_PATH_TYPE) RETURN FILE_NAMES_TYPE;



  -- Lists the paths of all the files within <code>directory_path</code>.
  -- 
  -- %raises NOT_FOUND If <code>directory_path</code> does not exist.
  -- %raises NON_DIRECTORY Raised if <code>directory_path</code> exists, but it is not a directory.
  FUNCTION list_file_paths(directory_path DIRECTORY_PATH_TYPE) RETURN FILE_PATHS_TYPE;



  -- Lists the names of all the subdirectories within <code>directory_path</code>.
  -- 
  -- %raises NOT_FOUND If <code>directory_path</code> does not exist.
  -- %raises NON_DIRECTORY Raised if <code>directory_path</code> exists, but it is not a directory.
  FUNCTION list_directory_names(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_NAMES_TYPE;



  -- Lists the paths of all the subdirectories within <code>directory_path</code>.
  -- 
  -- %raises NOT_FOUND If <code>directory_path</code> does not exist.
  -- %raises NON_DIRECTORY Raised if <code>directory_path</code> exists, but it is not a directory.
  FUNCTION list_directory_paths(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_PATHS_TYPE;



  FUNCTION list_root_directory_paths RETURN DIRECTORY_PATHS_TYPE;



  -- Copies the file at <code>source_file_path</code> to <code>destination_file_path</code>.
  -- 
  -- %raises NOT_FOUND If <code>source_file</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file <i>OR</i> <code>destination_file_path</code> exists, but it is not a file.
  -- %see copy_file_to_file
  PROCEDURE
    copy
    (
      source_file_path      FILE_PATH_TYPE,
      destination_file_path FILE_PATH_TYPE
    );



  -- Copies the file at <code>source_file_path</code> to the directory at <code>destination_directory_path</code>.
  -- 
  -- %param source_file_path The path of the file to be copied.
  -- %param destination_directory_path  The directory that the file will be copied into.
  -- %raises NOT_FOUND If <code>source_file</code> does not exist or if <code>destination_directory_path</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file.
  -- %raises NON_DIRECTORY If <code>destination_directory_path</code> exists, but it is not a directory.
  -- %see copy_file_to_directory
  PROCEDURE
    copy
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE
    );



  -- Copies the file at <code>source_file_path</code> to the directory at <code>destination_directory_path</code>.
  -- 
  -- %param source_file_path The path of the file to be copied.
  -- %param destination_directory_path  The directory that the file will be copied into.
  -- %param destination_file_path The path to the file at its new location.
  -- %raises NOT_FOUND If <code>source_file</code> does not exist or if <code>destination_directory_path</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file.
  -- %raises NON_DIRECTORY If <code>destination_directory_path</code> exists, but it is not a directory.
  -- %see copy_file_to_directory
  PROCEDURE
    copy
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE,
      destination_file_path      OUT FILE_PATH_TYPE
    );



  -- Copies the file at <code>source_file_path</code> to <code>destination_file_path</code>.
  -- 
  -- %raises NOT_FOUND If <code>source_file</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file <i>OR</i> <code>destination_file_path</code> exists, but it is not a file.
  -- %see copy_file
  PROCEDURE
    copy_file_to_file
    (
      source_file_path      FILE_PATH_TYPE,
      destination_file_path FILE_PATH_TYPE
    );



  -- Copies the file at <code>source_file_path</code> to the directory at <code>destination_directory_path</code>.
  -- 
  -- %param source_file_path The path of the file to be copied.
  -- %param destination_directory_path  The directory that the file will be copied into.
  -- %raises NOT_FOUND If <code>source_file</code> does not exist or if <code>destination_directory_path</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file.
  -- %raises NON_DIRECTORY If <code>destination_directory_path</code> exists, but it is not a directory.
  -- %see copy_file
  PROCEDURE
    copy_file_to_directory
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE
    );



  -- Copies the file at <code>source_file_path</code> to the directory at <code>destination_directory_path</code>.
  -- 
  -- %param source_file_path The path of the file to be copied.
  -- %param destination_directory_path  The directory that the file will be copied into.
  -- %param destination_file_path The path to the file at its new location.
  -- %raises NOT_FOUND If <code>source_file</code> does not exist or if <code>destination_directory_path</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file.
  -- %raises NON_DIRECTORY If <code>destination_directory_path</code> exists, but it is not a directory.
  -- %see copy_file
  PROCEDURE
    copy_file_to_directory
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE,
      destination_file_path      OUT FILE_PATH_TYPE
    );



  -- Moves the file at <code>source_file_path</code> to <code>destination_file_path</code>.
  -- 
  -- %raises NOT_FOUND If <code>source_file</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file <i>OR</i> <code>destination_file_path</code> exists, but it is not a file.
  -- %see move_file_to_file
  PROCEDURE
    move
    (
      source_file_path      FILE_PATH_TYPE,
      destination_file_path FILE_PATH_TYPE
    );



  -- Moves the file at <code>source_file_path</code> to the directory at <code>destination_directory_path</code>.
  -- 
  -- %param source_file_path The path of the file to be copied.
  -- %param destination_directory_path  The directory that the file will be copied into.
  -- %raises NOT_FOUND If <code>source_file</code> does not exist or if <code>destination_directory_path</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file.
  -- %raises NON_DIRECTORY If <code>destination_directory_path</code> exists, but it is not a directory.
  -- %see move_file_to_directory
  PROCEDURE
    move
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE
    );



  -- Moves the file at <code>source_file_path</code> to the directory at <code>destination_directory_path</code>.
  -- 
  -- %param source_file_path The path of the file to be copied.
  -- %param destination_directory_path  The directory that the file will be copied into.
  -- %param destination_file_path The path to the file at its new location.
  -- %raises NOT_FOUND If <code>source_file</code> does not exist or if <code>destination_directory_path</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file.
  -- %raises NON_DIRECTORY If <code>destination_directory_path</code> exists, but it is not a directory.
  -- %see move_file_to_directory
  PROCEDURE
    move
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE,
      destination_file_path      OUT FILE_PATH_TYPE
    );



  -- Moves the file at <code>source_file_path</code> to <code>destination_file_path</code>.
  -- 
  -- %raises NOT_FOUND If <code>source_file</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file <i>OR</i> <code>destination_file_path</code> exists, but it is not a file.
  -- %see move_file
  PROCEDURE
    move_file_to_file
    (
      source_file_path      FILE_PATH_TYPE,
      destination_file_path FILE_PATH_TYPE
    );



  -- Moves the file at <code>source_file_path</code> to the directory at <code>destination_directory_path</code>.
  -- 
  -- %param source_file_path The path of the file to be copied.
  -- %param destination_directory_path  The directory that the file will be copied into.
  -- %raises NOT_FOUND If <code>source_file</code> does not exist or if <code>destination_directory_path</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file.
  -- %raises NON_DIRECTORY If <code>destination_directory_path</code> exists, but it is not a directory.
  -- %see move_file
  PROCEDURE
    move_file_to_directory
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE
    );



  -- Moves the file at <code>source_file_path</code> to the directory at <code>destination_directory_path</code>.
  -- 
  -- %param source_file_path The path of the file to be copied.
  -- %param destination_directory_path  The directory that the file will be copied into.
  -- %param destination_file_path The path to the file at its new location.
  -- %raises NOT_FOUND If <code>source_file</code> does not exist or if <code>destination_directory_path</code> does not exist.
  -- %raises NON_FILE If <code>source_file_path</code> exists, but it is not a file.
  -- %raises NON_DIRECTORY If <code>destination_directory_path</code> exists, but it is not a directory.
  -- %see move_file
  PROCEDURE
    move_file_to_directory
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE,
      destination_file_path      OUT FILE_PATH_TYPE
    );



  -- Sets the "last update" date of the file or directory located at <code>path</code> to the current time.
  -- 
  -- %param path
  -- %raises NOT_FOUND Raised if <code>path</code> does not exist.
  PROCEDURE touch(path PATH_TYPE);



  -- Sets the "last update" date of the file located at <code>file_path</code> to the current time.
  --
  -- %param file_path
  -- %raises NON_FILE Raised if <code>file_path</code> exists, but is not a file
  PROCEDURE touch_file(file_path FILE_PATH_TYPE);



  -- Sets the "last update" date of the directory located at <code>directory_path</code> to the current time.
  --
  -- %param directory_path
  -- %raises NON_DIRECTORY Raised if <code>directory_path</code> exists, but is not a directory
  PROCEDURE touch_directory(directory_path DIRECTORY_PATH_TYPE);



  -- Opens the file at <code>file_path</code> for reading of <i>bytes</i>.
  -- 
  -- %param file_path
  -- %param buffer_size
  -- %raises NOT_FOUND Raised if the file at <code>file_path</code> does not exist.
  -- %raises NON_FILE Raised if <code>file_path</code> exists, but it is not a file.
  -- %return The file handle
  -- %see close_file_handle
  FUNCTION
    open_binary_file_for_reading
    (
      file_path   FILE_PATH_TYPE,
      buffer_size BINARY_INTEGER DEFAULT NULL
    )
    RETURN FILE_HANDLE_TYPE;



  -- Opens the file at <code>file_path</code> for writing of <i>bytes</i>.
  -- 
  -- %param file_path
  -- %param buffer_size
  -- %raises NOT_FOUND Raised if the file at <code>file_path</code> does not exist.
  -- %raises NON_FILE Raised if <code>file_path</code> exists, but it is not a file.
  -- %return The file handle
  -- %see flush_file_handle
  -- %see close_file_handle
  FUNCTION
    open_binary_file_for_writing
    (
      file_path   FILE_PATH_TYPE,
      buffer_size BINARY_INTEGER DEFAULT NULL
    )
    RETURN FILE_HANDLE_TYPE;



  -- Opens the file at <code>file_path</code> for reading of <i>characters</i>.
  -- 
  -- %param file_path
  -- %param charset_name
  -- %param buffer_size
  -- %raises NOT_FOUND Raised if the file at <code>file_path</code> does not exist.
  -- %raises NON_FILE Raised if <code>file_path</code> exists, but it is not a file.
  -- %return The file handle
  -- %see read_line
  -- %see close_file_handle
  FUNCTION
    open_textual_file_for_reading
    (
      file_path    FILE_PATH_TYPE,
      charset_name CHARSET_NAME_TYPE DEFAULT NULL,
      buffer_size  BINARY_INTEGER DEFAULT NULL
    )
    RETURN FILE_HANDLE_TYPE;



  -- Opens the file at <code>file_path</code> for writing of <i>characters</i>.
  -- 
  -- %param file_path
  -- %param charset_name
  -- %param buffer_size
  -- %raises NOT_FOUND Raised if the file at <code>file_path</code> does not exist.
  -- %raises NON_FILE Raised if <code>file_path</code> exists, but it is not a file.
  -- %return The file handle
  -- %see write_line
  -- %see flush_file_handle
  -- %see close_file_handle
  FUNCTION
    open_textual_file_for_writing
    (
      file_path    FILE_PATH_TYPE,
      charset_name CHARSET_NAME_TYPE DEFAULT NULL,
      buffer_size  BINARY_INTEGER DEFAULT NULL
    )
    RETURN FILE_HANDLE_TYPE;



  FUNCTION has_more_lines(textual_file_handle FILE_HANDLE_TYPE) RETURN BOOLEAN;

  FUNCTION read_line(textual_file_handle FILE_HANDLE_TYPE) RETURN VARCHAR2;

  PROCEDURE write_line(textual_file_handle FILE_HANDLE_TYPE);

  PROCEDURE write_line(textual_file_handle FILE_HANDLE_TYPE, text VARCHAR2);



  FUNCTION read_lines(file_path FILE_PATH_TYPE) RETURN FILE_LINES_TYPE;

  FUNCTION read_lines(file_path FILE_PATH_TYPE, charset_name CHARSET_NAME_TYPE) RETURN FILE_LINES_TYPE;



  -- Forces any buffered bytes or characters to be written out.
  -- 
  -- %param file_handle
  PROCEDURE flush_file_handle(file_handle FILE_HANDLE_TYPE);



  -- %param file_handle
  PROCEDURE close_file_handle(file_handle FILE_HANDLE_TYPE);



  -- Issues 
  PROCEDURE
    grant_permissions
    (
      path       PATH_TYPE,
      recursive  BOOLEAN DEFAULT FALSE,
      readable   BOOLEAN DEFAULT FALSE,
      writable   BOOLEAN DEFAULT FALSE,
      executable BOOLEAN DEFAULT FALSE,
      deletable  BOOLEAN DEFAULT FALSE
    );



END FS;
/
CREATE OR REPLACE PACKAGE BODY INTERFACE.FS IS



  VARCHAR_TABLE_TYPE_NAME CONSTANT ALL_TYPES.TYPE_NAME%TYPE := 'FS_VARCHAR_TABLE_TYPE';
  ERROR_TYPE_NAME         CONSTANT ALL_TYPES.TYPE_NAME%TYPE := 'FS_ERROR_TYPE';
  FILE_HANDLE_TYPE_NAME   CONSTANT ALL_TYPES.TYPE_NAME%TYPE := 'FS_FILE_HANDLE_TYPE';



  SUBTYPE status_type IS BINARY_INTEGER;



  FUNCTION to_boolean(number_value NUMBER) RETURN BOOLEAN IS
  BEGIN
    RETURN
      CASE
        WHEN number_value = 0     THEN FALSE
        WHEN number_value = 1     THEN TRUE
        WHEN number_value IS NULL THEN NULL
      END;
  END;



  -- Returns <code>TRUE</code> if <code>status</code> represents successful completion.
  FUNCTION success(status STATUS_TYPE) RETURN BOOLEAN IS
  BEGIN
    RETURN status = 1;
  END;



  -- Returns <code>TRUE</code> if <code>status</code> represents failed completion.
  FUNCTION failure(status STATUS_TYPE) RETURN BOOLEAN IS
  BEGIN
    RETURN status = 0;
  END;



  PROCEDURE raise_error_if_failure(status STATUS_TYPE, error ERROR_TYPE) IS
  BEGIN
    IF failure(status) THEN
      raise_application_error(error.code, error.message, TRUE);
    END IF;
  END;




  FUNCTION name_java(path FILE_PATH_TYPE, name OUT FILE_NAME_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.name(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION name(path PATH_TYPE) RETURN NAME_TYPE IS
    name NAME_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(name_java(path, name, error), error);
    RETURN name;
  END;




  FUNCTION base_java(name NAME_TYPE, base OUT NAME_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.base(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION base(name NAME_TYPE) RETURN NAME_TYPE IS
    base NAME_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(base_java(name, base, error), error);
    RETURN base;
  END;



  FUNCTION extension_java(name NAME_TYPE, extension OUT NAME_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.extension(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION extension(name NAME_TYPE) RETURN NAME_TYPE IS
    extension NAME_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(extension_java(name, extension, error), error);
    RETURN extension;
  END;



  FUNCTION exists_java(path PATH_TYPE, path_exists OUT BINARY_INTEGER, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.exists(java.lang.String, int[], plsqlfs.FileSystemException[]) return int';

  FUNCTION exists(path PATH_TYPE) RETURN BOOLEAN IS
    path_exists BINARY_INTEGER;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(exists_java(path, path_exists, error), error);
    RETURN to_boolean(path_exists);
  END;



  FUNCTION file_exists_java(file_path FILE_PATH_TYPE, file_path_exists OUT BINARY_INTEGER, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.fileExists(java.lang.String, int[], plsqlfs.FileSystemException[]) return int';

  FUNCTION file_exists(file_path FILE_PATH_TYPE) RETURN BOOLEAN IS
    file_path_exists BINARY_INTEGER;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(file_exists_java(file_path, file_path_exists, error), error);
    RETURN to_boolean(file_path_exists);
  END;



  FUNCTION directory_exists_java(directory_path DIRECTORY_PATH_TYPE, directory_path_exists OUT BINARY_INTEGER, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.directoryExists(java.lang.String, int[], plsqlfs.FileSystemException[]) return int';

  FUNCTION directory_exists(directory_path DIRECTORY_PATH_TYPE) RETURN BOOLEAN IS
    directory_path_exists BINARY_INTEGER;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(directory_exists_java(directory_path, directory_path_exists, error), error);
    RETURN to_boolean(directory_path_exists);
  END;




  FUNCTION append_to_path_java(base_path PATH_TYPE, relative_path PATH_TYPE, new_path OUT PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.appendToPath(java.lang.String, java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION append_to_path(base_path PATH_TYPE, relative_path PATH_TYPE) RETURN PATH_TYPE IS
    new_path PATH_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(append_to_path_java(base_path, relative_path, new_path, error), error);
    RETURN new_path;
  END;



  FUNCTION file_name_java(file_path FILE_PATH_TYPE, file_name OUT FILE_NAME_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.fileName(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION file_name(file_path FILE_PATH_TYPE) RETURN FILE_NAME_TYPE IS
    file_name FILE_NAME_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(file_name_java(file_path, file_name, error), error);
    RETURN file_name;
  END;




  FUNCTION file_size_java(file_path FILE_PATH_TYPE, file_size OUT BINARY_INTEGER, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.fileSize(java.lang.String, long[], plsqlfs.FileSystemException[]) return int';

  FUNCTION file_size(file_path FILE_PATH_TYPE) RETURN NUMBER IS
    file_size BINARY_INTEGER;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(file_size_java(file_path, file_size, error), error);
    RETURN file_size;
  END;



  FUNCTION directory_name_java(directory_path FILE_PATH_TYPE, directory_name OUT FILE_NAME_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.directoryName(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION directory_name(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_NAME_TYPE IS
    directory_name DIRECTORY_NAME_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(directory_name_java(directory_path, directory_name, error), error);
    RETURN directory_name;
  END;



  /*
   * PATHS
   */

  FUNCTION resolve_path_java(path PATH_TYPE, resolved_path OUT PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.resolvePath(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION resolve_path(path PATH_TYPE) RETURN PATH_TYPE IS
    resolved_path PATH_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(resolve_path_java(path, resolved_path, error), error);
    RETURN resolved_path;
  END;



  FUNCTION absolute_path_java(path PATH_TYPE, absolute_path OUT PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.absolutePath(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION absolute_path(path PATH_TYPE) RETURN PATH_TYPE IS
    absolute_path PATH_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(absolute_path_java(path, absolute_path, error), error);
    RETURN absolute_path;
  END;



  FUNCTION canonical_path_java(path PATH_TYPE, canonical_path OUT PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.canonicalPath(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION canonical_path(path PATH_TYPE) RETURN PATH_TYPE IS
    canonical_path PATH_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(canonical_path_java(path, canonical_path, error), error);
    RETURN canonical_path;
  END;



  /*
   * FILE PATHS
   */

  FUNCTION resolve_file_path_java(file_path FILE_PATH_TYPE, resolved_file_path OUT FILE_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.resolveFilePath(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION resolve_file_path(file_path FILE_PATH_TYPE) RETURN FILE_PATH_TYPE IS
    resolved_file_path FILE_PATH_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(resolve_file_path_java(file_path, resolved_file_path, error), error);
    RETURN resolved_file_path;
  END;



  FUNCTION absolute_file_path_java(file_path FILE_PATH_TYPE, absolute_file_path OUT FILE_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.absoluteFilePath(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION absolute_file_path(file_path FILE_PATH_TYPE) RETURN FILE_PATH_TYPE IS
    absolute_file_path FILE_PATH_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(absolute_file_path_java(file_path, absolute_file_path, error), error);
    RETURN absolute_file_path;
  END;



  FUNCTION canonical_file_path_java(file_path FILE_PATH_TYPE, canonical_file_path OUT FILE_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.canonicalFilePath(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION canonical_file_path(file_path FILE_PATH_TYPE) RETURN FILE_PATH_TYPE IS
    canonical_file_path FILE_PATH_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(canonical_file_path_java(file_path, canonical_file_path, error), error);
    RETURN canonical_file_path;
  END;



  /*
   * DIRECTORY PATHS
   */

  FUNCTION resolve_directory_path_java(directory_path DIRECTORY_PATH_TYPE, resolved_directory_path OUT DIRECTORY_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.resolveDirectoryPath(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION resolve_directory_path(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_PATH_TYPE IS
    resolved_directory_path DIRECTORY_PATH_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(resolve_directory_path_java(directory_path, resolved_directory_path, error), error);
    RETURN resolved_directory_path;
  END;



  FUNCTION absolute_directory_path_java(directory_path DIRECTORY_PATH_TYPE, absolute_directory_path OUT DIRECTORY_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.absoluteDirectoryPath(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION absolute_directory_path(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_PATH_TYPE IS
    absolute_directory_path DIRECTORY_PATH_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(absolute_directory_path_java(directory_path, absolute_directory_path, error), error);
    RETURN absolute_directory_path;
  END;



  FUNCTION canonical_directory_path_java(directory_path DIRECTORY_PATH_TYPE, canonical_directory_path OUT DIRECTORY_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.canonicalDirectoryPath(java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION canonical_directory_path(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_PATH_TYPE IS
    canonical_directory_path DIRECTORY_PATH_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(canonical_directory_path_java(directory_path, canonical_directory_path, error), error);
    RETURN canonical_directory_path;
  END;



  FUNCTION delete_java(path PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.delete(java.lang.String, plsqlfs.FileSystemException[]) return int';

  PROCEDURE delete(path PATH_TYPE) IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(delete_java(path, error), error);
  END;



  FUNCTION delete_file_java(file_path FILE_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.deleteFile(java.lang.String, plsqlfs.FileSystemException[]) return int';

  PROCEDURE delete_file(file_path FILE_PATH_TYPE) IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(delete_file_java(file_path, error), error);
  END;



  FUNCTION delete_directory_java(directory_path DIRECTORY_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.deleteDirectory(java.lang.String, plsqlfs.FileSystemException[]) return int';

  PROCEDURE delete_directory(directory_path DIRECTORY_PATH_TYPE) IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(delete_directory_java(directory_path, error), error);
  END;



  FUNCTION list_names_java(directory_path DIRECTORY_PATH_TYPE, names OUT FS_VARCHAR_TABLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.listNames(java.lang.String, oracle.sql.ARRAY[], plsqlfs.FileSystemException[]) return int';

  FUNCTION list_names(directory_path DIRECTORY_PATH_TYPE) RETURN NAMES_TYPE IS
    names NAMES_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(list_names_java(directory_path, names, error), error);
    RETURN names;
  END;



  FUNCTION list_pattern_names_java(directory_path DIRECTORY_PATH_TYPE, pattern VARCHAR2, names OUT FS_VARCHAR_TABLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.listNames(java.lang.String, java.lang.String, oracle.sql.ARRAY[], plsqlfs.FileSystemException[]) return int';

  FUNCTION list_names(directory_path DIRECTORY_PATH_TYPE, pattern VARCHAR2) RETURN NAMES_TYPE IS
    names NAMES_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(list_pattern_names_java(directory_path, pattern, names, error), error);
    RETURN names;
  END;



  FUNCTION list_paths_java(directory_path DIRECTORY_PATH_TYPE, paths OUT FS_VARCHAR_TABLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.listPaths(java.lang.String, oracle.sql.ARRAY[], plsqlfs.FileSystemException[]) return int';

  FUNCTION list_paths(directory_path DIRECTORY_PATH_TYPE) RETURN PATHS_TYPE IS
    paths PATHS_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(list_paths_java(directory_path, paths, error), error);
    RETURN paths;
  END;



  FUNCTION list_pattern_paths_java(directory_path DIRECTORY_PATH_TYPE, pattn VARCHAR2, paths OUT FS_VARCHAR_TABLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.listPaths(java.lang.String, java.lang.String, oracle.sql.ARRAY[], plsqlfs.FileSystemException[]) return int';

  FUNCTION list_paths(directory_path DIRECTORY_PATH_TYPE, pattern VARCHAR2) RETURN PATHS_TYPE IS
    paths PATHS_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(list_pattern_paths_java(directory_path, pattern, paths, error), error);
    RETURN paths;
  END;



  FUNCTION list_file_names_java(directory_path DIRECTORY_PATH_TYPE, file_names OUT FS_VARCHAR_TABLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.listFileNames(java.lang.String, oracle.sql.ARRAY[], plsqlfs.FileSystemException[]) return int';

  FUNCTION list_file_names(directory_path DIRECTORY_PATH_TYPE) RETURN FILE_NAMES_TYPE IS
    file_names FILE_NAMES_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(list_file_names_java(directory_path, file_names, error), error);
    RETURN file_names;
  END;



  FUNCTION list_file_paths_java(directory_path DIRECTORY_PATH_TYPE, file_paths OUT FS_VARCHAR_TABLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.listFilePaths(java.lang.String, oracle.sql.ARRAY[], plsqlfs.FileSystemException[]) return int';

  FUNCTION list_file_paths(directory_path DIRECTORY_PATH_TYPE) RETURN FILE_PATHS_TYPE IS
    file_paths FILE_PATHS_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(list_file_paths_java(directory_path, file_paths, error), error);
    RETURN file_paths;
  END;



  FUNCTION list_directory_names_java(directory_path DIRECTORY_PATH_TYPE, directory_names OUT FS_VARCHAR_TABLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.listDirectoryNames(java.lang.String, oracle.sql.ARRAY[], plsqlfs.FileSystemException[]) return int';

  FUNCTION list_directory_names(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_NAMES_TYPE IS
    directory_names DIRECTORY_NAMES_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(list_directory_names_java(directory_path, directory_names, error), error);
    RETURN directory_names;
  END;



  FUNCTION list_directory_paths_java(directory_path DIRECTORY_PATH_TYPE, directory_paths OUT FS_VARCHAR_TABLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.listDirectoryPaths(java.lang.String, oracle.sql.ARRAY[], plsqlfs.FileSystemException[]) return int';

  FUNCTION list_directory_paths(directory_path DIRECTORY_PATH_TYPE) RETURN DIRECTORY_PATHS_TYPE IS
    directory_paths DIRECTORY_PATHS_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(list_directory_paths_java(directory_path, directory_paths, error), error);
    RETURN directory_paths;
  END;



  FUNCTION list_root_directory_paths_java(root_directory_paths OUT FS_VARCHAR_TABLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.listRootDirectoryPaths(oracle.sql.ARRAY[], plsqlfs.FileSystemException[]) return int';

  FUNCTION list_root_directory_paths RETURN DIRECTORY_PATHS_TYPE IS
    root_directory_paths DIRECTORY_PATHS_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(list_root_directory_paths_java(root_directory_paths, error), error);
    RETURN root_directory_paths;
  END;




  PROCEDURE
    copy
    (
      source_file_path      FILE_PATH_TYPE,
      destination_file_path FILE_PATH_TYPE
    )
    IS
  BEGIN
    copy_file_to_file(
        source_file_path      => source_file_path,
        destination_file_path => destination_file_path
      );
  END;



  -- %see copy_file_to_directory
  PROCEDURE
    copy
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE
    )
    IS
  BEGIN
    copy_file_to_directory(
        source_file_path           => source_file_path,
        destination_directory_path => destination_directory_path
      );
  END;



  -- %see copy_file_to_directory
  PROCEDURE
    copy
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE,
      destination_file_path      OUT FILE_PATH_TYPE
    )
    IS
  BEGIN
    copy_file_to_directory(
        source_file_path           => source_file_path,
        destination_directory_path => destination_directory_path,
        destination_file_path      => destination_file_path
      );
  END;



  FUNCTION copy_file_to_file_java(source_file_path FILE_PATH_TYPE, destination_file_path FILE_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.copyFileToFile(java.lang.String, java.lang.String, plsqlfs.FileSystemException[]) return int';

  PROCEDURE
    copy_file_to_file
    (
      source_file_path      FILE_PATH_TYPE,
      destination_file_path FILE_PATH_TYPE
    )
  IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(copy_file_to_file_java(source_file_path, destination_file_path, error), error);
  END;



  -- %see copy_file
  PROCEDURE
    copy_file_to_directory
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE
    )
  IS
    destination_file_path FILE_PATH_TYPE;
  BEGIN
    copy_file_to_directory(
        source_file_path           => source_file_path,
        destination_directory_path => destination_directory_path,
        destination_file_path      => destination_file_path
      );
  END;



  FUNCTION copy_file_to_directory_java(source_file_path FILE_PATH_TYPE, destination_directory_path DIRECTORY_PATH_TYPE, destination_file_path OUT FILE_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.copyFileToDirectory(java.lang.String, java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  -- %see copy_file
  PROCEDURE
    copy_file_to_directory
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE,
      destination_file_path      OUT FILE_PATH_TYPE
    )
  IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(copy_file_to_directory_java(source_file_path, destination_directory_path, destination_file_path, error), error);
  END;




  PROCEDURE
    move
    (
      source_file_path      FILE_PATH_TYPE,
      destination_file_path FILE_PATH_TYPE
    )
    IS
  BEGIN
    move_file_to_file(
        source_file_path      => source_file_path,
        destination_file_path => destination_file_path
      );
  END;



  -- %see move_file_to_directory
  PROCEDURE
    move
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE
    )
    IS
  BEGIN
    move_file_to_directory(
        source_file_path           => source_file_path,
        destination_directory_path => destination_directory_path
      );
  END;



  -- %see move_file_to_directory
  PROCEDURE
    move
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE,
      destination_file_path      OUT FILE_PATH_TYPE
    )
    IS
  BEGIN
    move_file_to_directory(
        source_file_path           => source_file_path,
        destination_directory_path => destination_directory_path,
        destination_file_path      => destination_file_path
      );
  END;



  FUNCTION move_file_to_file_java(source_file_path FILE_PATH_TYPE, destination_file_path FILE_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.moveFileToFile(java.lang.String, java.lang.String, plsqlfs.FileSystemException[]) return int';

  PROCEDURE
    move_file_to_file
    (
      source_file_path      FILE_PATH_TYPE,
      destination_file_path FILE_PATH_TYPE
    )
  IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(move_file_to_file_java(source_file_path, destination_file_path, error), error);
  END;



  -- %see move_file
  PROCEDURE
    move_file_to_directory
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE
    )
  IS
    destination_file_path FILE_PATH_TYPE;
  BEGIN
    move_file_to_directory(
        source_file_path           => source_file_path,
        destination_directory_path => destination_directory_path,
        destination_file_path      => destination_file_path
      );
  END;



  FUNCTION move_file_to_directory_java(source_file_path FILE_PATH_TYPE, destination_directory_path DIRECTORY_PATH_TYPE, destination_file_path OUT FILE_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.moveFileToDirectory(java.lang.String, java.lang.String, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  -- %see move_file
  PROCEDURE
    move_file_to_directory
    (
      source_file_path           FILE_PATH_TYPE,
      destination_directory_path DIRECTORY_PATH_TYPE,
      destination_file_path      OUT FILE_PATH_TYPE
    )
  IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(move_file_to_directory_java(source_file_path, destination_directory_path, destination_file_path, error), error);
  END;




  FUNCTION touch_java(path PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.touch(java.lang.String, plsqlfs.FileSystemException[]) return int';

  PROCEDURE touch(path PATH_TYPE) IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(touch_java(path, error), error);
  END;



  FUNCTION touch_file_java(file_path FILE_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.touchFile(java.lang.String, plsqlfs.FileSystemException[]) return int';

  PROCEDURE touch_file(file_path FILE_PATH_TYPE) IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(touch_file_java(file_path, error), error);
  END;



  FUNCTION touch_directory_java(directory_path DIRECTORY_PATH_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.touchDirectory(java.lang.String, plsqlfs.FileSystemException[]) return int';

  PROCEDURE touch_directory(directory_path DIRECTORY_PATH_TYPE) IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(touch_directory_java(directory_path, error), error);
  END;



  FUNCTION open_file_java(file_path FILE_PATH_TYPE, file_handle OUT FILE_HANDLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.openFile(java.lang.String, int[], plsqlfs.FileSystemException[]) return int';
  
  FUNCTION open_file(file_path FILE_PATH_TYPE) RETURN FILE_HANDLE_TYPE IS
    file_handle FILE_HANDLE_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(open_file_java(file_path, file_handle, error), error);
    RETURN file_handle;
  END;



  FUNCTION flush_file_handle_java(file_handle FILE_HANDLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.flushFileHandle(plsqlfs.FileHandle, plsqlfs.FileSystemException[]) return int';
  
  PROCEDURE flush_file_handle(file_handle FILE_HANDLE_TYPE) IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(flush_file_handle_java(file_handle, error), error);
  END;



  FUNCTION close_file_handle_java(file_handle FILE_HANDLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.closeFileHandle(plsqlfs.FileHandle, plsqlfs.FileSystemException[]) return int';
  
  PROCEDURE close_file_handle(file_handle FILE_HANDLE_TYPE) IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(close_file_handle_java(file_handle, error), error);
  END;



  FUNCTION has_more_lines_java(file_handle FILE_HANDLE_TYPE, result OUT BINARY_INTEGER, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.hasMoreLines(plsqlfs.FileHandle, int[], plsqlfs.FileSystemException[]) return int';

  FUNCTION has_more_lines(textual_file_handle FILE_HANDLE_TYPE) RETURN BOOLEAN IS
    result BINARY_INTEGER;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(has_more_lines_java(textual_file_handle, result, error), error);
    RETURN to_boolean(result);
  END;



  FUNCTION read_line_java(file_handle FILE_HANDLE_TYPE, line OUT VARCHAR2, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.readLine(plsqlfs.FileHandle, java.lang.String[], plsqlfs.FileSystemException[]) return int';

  FUNCTION read_line(textual_file_handle FILE_HANDLE_TYPE) RETURN VARCHAR2 IS
    line FILE_LINE_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(read_line_java(textual_file_handle, line, error), error);
    RETURN line;
  END;



  FUNCTION read_lines_java(file_path FILE_PATH_TYPE, charset_name CHARSET_NAME_TYPE, lines OUT FS_VARCHAR_TABLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.readLines(java.lang.String, java.lang.String, oracle.sql.ARRAY[], plsqlfs.FileSystemException[]) return int';

  FUNCTION read_lines(file_path FILE_PATH_TYPE, charset_name CHARSET_NAME_TYPE) RETURN FILE_LINES_TYPE IS
    lines FILE_LINES_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(read_lines_java(file_path, charset_name, lines, error), error);
    RETURN lines;
  END;

  FUNCTION read_lines(file_path FILE_PATH_TYPE) RETURN FILE_LINES_TYPE IS
  BEGIN
    RETURN read_lines( file_path => file_path, charset_name => NULL );
  END;



  FUNCTION write_line_java(file_handle FILE_HANDLE_TYPE, text VARCHAR2, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.writeLine(plsqlfs.FileHandle, java.lang.String, plsqlfs.FileSystemException[]) return int';

  PROCEDURE write_line(textual_file_handle FILE_HANDLE_TYPE, text VARCHAR2) IS
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(write_line_java(textual_file_handle, text, error), error);
  END;

  PROCEDURE write_line(textual_file_handle FILE_HANDLE_TYPE) IS
  BEGIN
    write_line( textual_file_handle, '' );
  END;



  FUNCTION jopen_binary_file(file_path FILE_PATH_TYPE, file_handle OUT FS_FILE_HANDLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.openBinaryFile(java.lang.String, plsqlfs.FileHandle[], plsqlfs.FileSystemException[]) return int';

  FUNCTION open_binary_file(file_path FILE_PATH_TYPE) RETURN FILE_HANDLE_TYPE IS
    file_handle FILE_HANDLE_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(jopen_binary_file(file_path, file_handle, error), error);
    RETURN file_handle;
  END;



  FUNCTION jopen_binary_file_for_reading(file_path FILE_PATH_TYPE, buffer_size NUMBER, file_handle OUT FILE_HANDLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.openBinaryFileForReading(java.lang.String, java.lang.Integer, plsqlfs.FileHandle[], plsqlfs.FileSystemException[]) return int';

  FUNCTION open_binary_file_for_reading(file_path FILE_PATH_TYPE, buffer_size BINARY_INTEGER DEFAULT NULL) RETURN FILE_HANDLE_TYPE IS
    file_handle FILE_HANDLE_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(jopen_binary_file_for_reading(file_path, buffer_size, file_handle, error), error);
    RETURN file_handle;
  END;



  FUNCTION jopen_binary_file_for_writing(file_path FILE_PATH_TYPE, buffer_size NUMBER, file_handle OUT FILE_HANDLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.openBinaryFileForWriting(java.lang.String, java.lang.Integer, plsqlfs.FileHandle[], plsqlfs.FileSystemException[]) return int';

  FUNCTION open_binary_file_for_writing(file_path FILE_PATH_TYPE, buffer_size BINARY_INTEGER DEFAULT NULL) RETURN FILE_HANDLE_TYPE IS
    file_handle FILE_HANDLE_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(jopen_binary_file_for_writing(file_path, buffer_size, file_handle, error), error);
    RETURN file_handle;
  END;



  FUNCTION jopen_textual_file(file_path FILE_PATH_TYPE, charset_name VARCHAR2, file_handle OUT FILE_HANDLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.openTextualFile(java.lang.String, java.lang.String, plsqlfs.FileHandle[], plsqlfs.FileSystemException[]) return int';

  FUNCTION open_textual_file(file_path FILE_PATH_TYPE, charset_name CHARSET_NAME_TYPE) RETURN FILE_HANDLE_TYPE IS
    file_handle FILE_HANDLE_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(jopen_textual_file(file_path, charset_name, file_handle, error), error);
    RETURN file_handle;
  END;



  FUNCTION jopen_textual_file_for_reading(file_path FILE_PATH_TYPE, charset_name VARCHAR2, buffer_size BINARY_INTEGER, file_handle OUT FILE_HANDLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.openTextualFileForReading(java.lang.String, java.lang.String, int, plsqlfs.FileHandle[], plsqlfs.FileSystemException[]) return int';

  FUNCTION open_textual_file_for_reading(file_path FILE_PATH_TYPE, charset_name CHARSET_NAME_TYPE DEFAULT NULL, buffer_size BINARY_INTEGER DEFAULT NULL) RETURN FILE_HANDLE_TYPE IS
    file_handle FILE_HANDLE_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(jopen_textual_file_for_reading(file_path, charset_name, buffer_size, file_handle, error), error);
    RETURN file_handle;
  END;



  FUNCTION jopen_textual_file_for_writing(file_path FILE_PATH_TYPE, charset_name VARCHAR2, buffer_size BINARY_INTEGER, file_handle OUT FILE_HANDLE_TYPE, error OUT ERROR_TYPE) RETURN STATUS_TYPE
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.openTextualFileForWriting(java.lang.String, java.lang.String, int, plsqlfs.FileHandle[], plsqlfs.FileSystemException[]) return int';

  FUNCTION open_textual_file_for_writing(file_path FILE_PATH_TYPE, charset_name CHARSET_NAME_TYPE DEFAULT NULL, buffer_size BINARY_INTEGER DEFAULT NULL) RETURN FILE_HANDLE_TYPE IS
    file_handle FILE_HANDLE_TYPE;
    error ERROR_TYPE;
  BEGIN
    raise_error_if_failure(jopen_textual_file_for_writing(file_path, charset_name, buffer_size, file_handle, error), error);
    RETURN file_handle;
  END;



  FUNCTION split(text VARCHAR2) RETURN FS_VARCHAR_TABLE_TYPE IS
    lines FS_VARCHAR_TABLE_TYPE := FS_VARCHAR_TABLE_TYPE();
    from_position BINARY_INTEGER;
    to_position BINARY_INTEGER;
  BEGIN
    from_position := 1;
    
    LOOP
      to_position := instr(text, chr(10), from_position);
      IF to_position = 0 THEN
        -- Done
        lines.EXTEND(1);
        lines(lines.COUNT) := substr(text, from_position);
        EXIT;
      ELSE
        lines.EXTEND(1);
        lines(lines.COUNT) := substr(text, from_position, (to_position - from_position));
        from_position := to_position + 1;
      END IF;
    END LOOP;
    
    RETURN lines;
  END;



  PROCEDURE
    grant_permissions
    (
      path       PATH_TYPE,
      recursive  BOOLEAN DEFAULT FALSE,
      readable   BOOLEAN DEFAULT FALSE,
      writable   BOOLEAN DEFAULT FALSE,
      executable BOOLEAN DEFAULT FALSE,
      deletable  BOOLEAN DEFAULT FALSE
    )
  IS
    call_stack_lines FS_VARCHAR_TABLE_TYPE;
    delimiter VARCHAR2(1);
    actions VARCHAR2(1000);
    owner VARCHAR2(30);
    resolved_path PATH_TYPE;
    
    PROCEDURE append_action(action VARCHAR2) IS
    BEGIN
      actions := actions || delimiter || action;
      delimiter := ',';
    END;
    
  BEGIN
    call_stack_lines := split(dbms_utility.format_call_stack);
    FOR i IN call_stack_lines.FIRST .. call_stack_lines.LAST LOOP
      owner := regexp_replace(regexp_substr(call_stack_lines(i), 'package[[:space:]]+body[[:space:]]+(.+)\.FS'), 'package[[:space:]]+body[[:space:]]+(.+)\.FS', '\1');
      IF ( owner IS NOT NULL ) THEN
        EXIT;
      END IF;
    END LOOP;
    
    IF readable THEN
      append_action('read');
    END IF;
    
    IF writable THEN
      append_action('write');
    END IF;
    
    IF executable THEN
      append_action('executable');
    END IF;
    
    IF deletable THEN
      append_action('deletable');
    END IF;
    
    resolved_path := resolve_path(path);
    IF recursive THEN
      resolved_path := append_to_path(resolved_path, '-');
    END IF;
    
    dbms_output.put_line('BEGIN dbms_java.grant_permission(''' || owner || ''', ''SYS:java.io.FilePermission'', ''' || resolved_path || ''', ''' || actions || '''); END;');
    
    dbms_java.grant_permission(owner, 'SYS:java.io.FilePermission', resolved_path, actions);
  END;



  PROCEDURE init_varchar_table_type(name VARCHAR2)
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.setVarcharTableTypeName(java.lang.String)';



  PROCEDURE init_error_type(name VARCHAR2)
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.setErrorTypeName(java.lang.String)';



  PROCEDURE init_file_handle_type(name VARCHAR2)
    AS LANGUAGE JAVA
    NAME 'plsqlfs.StaticPlSqlFileSystem.setFileHandleTypeName(java.lang.String)';
  
BEGIN
  IF FALSE THEN
    init_varchar_table_type(VARCHAR_TABLE_TYPE_NAME);
    init_error_type(ERROR_TYPE_NAME);
    init_file_handle_type(FILE_HANDLE_TYPE_NAME);
  END IF;
END FS;
/
